#include <bits/stdc++.h>
#define int long long 
using namespace std;

const int maxn = 2e4 + 5;
int n, V;
int v[maxn], w[maxn], s[maxn];
int dp[maxn]; // 体积不超过 j 时 的最大值
int q[maxn]; // 模拟队列, 存放的是 体积值
int t[maxn]; // 临时数组


void solve(){
	cin >> n >> V;
	for (int i=1;i<=n;i++) {
		cin >> v[i] >> w[i] >> s[i];
	}
	
	for (int i=1;i<=n;i++) { // n 个物品
		// 对于 第 i 个
		memcpy(t, dp, sizeof(dp));
		
		
		for (int j = 0;j<v[i];j++) {
			int head = 0; // 队列
			int tail = -1;
			for (int k=j;k<=V;k+=v[i]) {
				dp[k] = t[k]; // 这个直接转移过来, 就表示当前物品一个都不放
				// 窗口是一个固定值, s[i], 现在窗口往后移动了, 不在窗口中的要删除
				// 不过, 每次窗口就移动一个, 所以, 这里面使用 if 就行
				while (head <= tail && head < (k-s[i]*v[i])) {
					head++;
				}
				
				// 队列里面有值的话, 直接使用最大值即可 (队头)
				if (head <= tail) {
					dp[k] = max(dp[k], t[q[head]]+((k-q[head])/v[i])*w[i]);
				}
				
				// 如果当前值, 比队列中的值还大, 就将队列中元素删除, 直到大于 当前值
				while(head <= tail &&  t[q[tail]] - (q[tail]-j)/v[i]*w[i] <= t[k] - (k-j)/v[i]*w[i]) {
					tail--;
				}
				
				q[++tail] = k;
			}
		}
	}
	
	int ans = 0; 
	for (int i=1;i<=V;i++) {
		ans = max(ans, dp[i]);
	}
	
	
	cout << ans << '\n'; 
	
}

signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	solve();
	return 0;
}

